package mongodb

import (
	"fmt"
	"iot-cloud-server/command"
	"sync"
	"time"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type MongoServer struct {
	session *mgo.Session
	wg      *sync.WaitGroup
}

func NewMongoServer(mongoURI string, wg *sync.WaitGroup) (*MongoServer, error) {
	var err error
	ms := new(MongoServer)
	fmt.Println("NewMongoServer Dial ", mongoURI)
	ms.session, err = mgo.Dial(mongoURI)
	ms.wg = wg
	if err != nil {
		return nil, err
	}
	return ms, nil
}

func (ms *MongoServer) Run(cmdChan chan *command.CommandData) {
	defer ms.wg.Done()
	for cmdData := range cmdChan {
		switch cmdData.Action {
		case command.InsertAction:
			fmt.Println("MongoServer Run InsertAction")
			userData := &command.UserData{Id_: bson.NewObjectId(),
				UserKey:   cmdData.UserKey,
				TimeStamp: time.Now().Format("2006-01-02 15:04:05"),
				Message:   cmdData.Message,
			}
			go ms.Insert(userData)
		case command.FindAction:
			fmt.Println("MongoServer Run FindAction")
			var userKey string = cmdData.UserKey
			var timeStamp string = cmdData.TimeStamp
			ms.wg.Add(1)
			go ms.QueryByTimeStamp(userKey, timeStamp)
		default:
			fmt.Println("MongoServer Run DefaultAction")
		}
	}
}

func (ms *MongoServer) Insert(userDataIf interface{}) {
	session := ms.session.Clone()
	defer session.Close()

	userData := userDataIf.(*command.UserData)
	fmt.Println("userData:", userData)
	collection := session.DB(command.DATABASE).C(command.COLLECTION)
	err := collection.Insert(userData)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Insert goroutine finished")
}

func (ms *MongoServer) QueryByTimeStamp(userKey string, timeStamp string) ([]command.UserData, error) {
	session := ms.session.Clone()
	defer session.Close()
	collection := session.DB(command.DATABASE).C(command.COLLECTION)
	var userDatas []command.UserData

	err := collection.Find(bson.M{"userkey": userKey, "timestamp": bson.M{"$lte": timeStamp}}).Limit(10).All(&userDatas)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	fmt.Println("QueryByTimeStamp goroutine finished")
	return userDatas, nil
}
